package com.tianji.learning.task;

import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.po.PointsBoardSeason;
import com.tianji.learning.service.IPointsBoardSeasonService;
import com.tianji.learning.service.IPointsBoardService;
import com.tianji.learning.utils.TableInfoContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class PointsBoardPersistentHandler {
    private final IPointsBoardSeasonService seasonService;
    private final IPointsBoardService pointsBoardService;
    private final StringRedisTemplate redisTemplate;

    /**
     * 创建上赛季（上个月）榜单表
     */
    // @Scheduled(cron = "0 0 3 1 * ?") // 每月1号，凌晨3点执行
    // @Scheduled(cron = "0 28 21 30 9 ?") // 单机版，定时任务调度
    @XxlJob("createTableJob")
    public void createPointsBoardTableOfLastSeason() {
        log.debug("创建上个赛季榜单表 执行了");
        // 1.获取上月时间
        LocalDate time = LocalDate.now().minusMonths(1);
        // 2.查询赛季id begin_time <= time and end_time >=time
        PointsBoardSeason one = seasonService.lambdaQuery().le(PointsBoardSeason::getBeginTime, time)
                .ge(PointsBoardSeason::getEndTime, time).one();
        log.debug("createPointsBoardTableOfLastSeason上赛季信息：{}", one);
        if (one == null) {
            // 赛季不存在
            return;
        }
        // 3.创建表 points_board_11
        pointsBoardService.createPointsBoardTableBySeason(one.getId());
    }

    /**
     * 持久化上赛季（上个月）的榜单 redis->mysql
     */
    @XxlJob("savePointsBoard2DB")
    public void savePointsBoard2DB() {
        log.debug("持久化上赛季（上个月）的榜单 redis->mysql 执行了");
        // 1.获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);
        // 2.计算动态表名
        // 2.1.查询赛季信息
        PointsBoardSeason one = seasonService.lambdaQuery().le(PointsBoardSeason::getBeginTime, time)
                .ge(PointsBoardSeason::getEndTime, time).one();
        log.debug("savePointsBoard2DB上赛季信息：{}", one);
        Integer season = one.getId();
        // 2.2.将表名存入ThreadLocal
        String tableName = "points_board_" + season;
        log.debug("表名：{}",tableName);
        TableInfoContext.setInfo(tableName);
        // 3.查询榜单数据
        // 3.1.拼接KEY
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + time.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER);
        // 3.2.查询数据
        int index = XxlJobHelper.getShardIndex();
        int total = XxlJobHelper.getShardTotal();
        int pageNo = index + 1; // 起始页，就是分片序号+1
        int pageSize = 1000;
        while (true) {
            List<PointsBoard> boardList = pointsBoardService.queryCurrentBoardList(key, pageNo, pageSize);
            if (CollUtils.isEmpty(boardList)) {
                break;
            }
            // 4.持久化到数据库
            // 4.1.把排名信息写入id
            boardList.forEach(b -> {
                b.setId(b.getRank().longValue());
                b.setRank(null);
            });
            // 4.2.持久化
            pointsBoardService.saveBatch(boardList);
            // 5.翻页，跳过N个页，N就是分片数量
            pageNo += total;
        }
        // 任务结束，移除动态表名
        TableInfoContext.remove();
    }

    /**
     * 清理上个赛季（上个月）的Redis排行榜数据
     */
    @XxlJob("clearPointsBoardFromRedis")
    public void clearPointsBoardFromRedis() {
        log.debug("清理上个赛季（上个月）的Redis排行榜数据 执行了");
        // 1.获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);
        // 2.计算key
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + time.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER);
        // 3.删除
        redisTemplate.unlink(key);
    }
}
